package jers.impl;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import jers.Callback;
import jers.JERS;
import jers.Job;
import jers.Result;
import jers.Service;
import jers.util.ThreadPool;
import jers.util.Utility;


/**
 * Classe que implementa a interface {@link Service}.
 * <p>
 * Esta extende a classe {@link UnicastRemoteObject} para prover 
 * os servicos remotos via RMI.
 * </p>
 * 
 * @see {@link UnicastRemoteObject}, {@link SystemFactory}, {@link Service}
 * 
 * @author 
 * 		<a href="mailto:felipe.zappala@gmail.com">
 * 			Luis Felipe Zappala
 * 		</a> [ <a href="http://lncc.br/ist">ISTCC-P</a> / 2009 ]
 */
final class RemoteService extends UnicastRemoteObject implements Service {

	/** O ID serial da versao da classe */
	private static final long serialVersionUID = 6482711222977371435L;
	
	/**
	 * O construtor padrao do objeto
	 * 
	 * @throws 
	 * 		RemoteException caso ocorra algum erro
	 */
	public RemoteService() throws RemoteException {
		super(); 
	}

	public void dispatch(Job job, Callback callback) throws RemoteException {
		if (job == null) {
			throw new RemoteException("Parameter job is null");
		}
		if (callback == null) {
			throw new RemoteException("Parameter callback is null");
		}
		executeOnThread(createRunnableTask(job, callback));
	}
	
	public Result execute(Job job) throws RemoteException {
		if (job == null) {
			throw new RemoteException("Parameter job is null");
		}
		job.run();
		return job.results();
	}

	/**
	 * Executa o tabalho in uma nova thread usando o pool.
	 * 
	 * @param 
	 * 		job - O trabalho a ser executado.
	 */
	private static void executeOnThread(Runnable job) {
		ThreadPool threadPool = JERS.factory.newThreadPool();
		
		if (!threadPool.isStarted()) {
			threadPool.start();
		}
		threadPool.execute(job);
	}

	/**
	 * Cria um objeto {@link Runnable} anonimo para executar 
	 * o trabalho e invocar o callback.
	 * 
	 * @param  
	 * 		job - O trabalho a ser executado.
	 * @param  
	 * 		callback - A callback a ser executada.
	 * @return
	 * 		Uma instancia de {@link Runnable}
	 */
	private Runnable createRunnableTask(final Job job, final Callback callback){
		return new Runnable() {
			public void run() {
				try {
					job.run();
					callback.call(job.results());
					
				} catch (Exception e) {
					JERS.log.error(e, "Error on execute dispached job [ ",
							job, " ] and invoke callback [ ", callback, " ].");
				}
			}
		}; 
	}
	
	/**
	 * Retorna uma representacao {@link String} do objeto.
	 * <p>
	 * <b>Formato:</b><br>
	 * 		<code>ClassName{attributeA:valueA,...,attributeN:valueN}</code>
	 * </p>
	 * @return 
	 * 		A representacao {@link String} do objeto.
	 */
	@Override
	public String toString() {
    	return Utility.toString(this);
    }
	
}
